1、your react app suddenly becomes slow after adding new features, how do you find and fix the issue?

可以这样类比来想:think of it like you phone is slowing down after you install too many apps, you need to find out which app is using the resourses and is making you phone slow.

1、we can use chrome devtools, and in the performance tab, and see what is taking the most time.

2、we can use react devtools chrome extension, we can track unneccessary rerenders or infinite loop of rerenders.

3、we can use React.memo and useCallback to making app fast and tracking where is slow.

4、I will check if there are any large amount of data to render at once. usually we render only the visible amount of data, use packages like react.window or react.virtulized.

5、avoid inline functions and objects。

Inline functions and objects are recreated on every render, which can cause child components to re-render unnecessarily — especially if those children depend on referential equality (React.memo, dependency arrays, etc.).

Example problem:

Every render:

So Child thinks props changed → re-renders every time, even if nothing actually changed.

How to fix it:

①Use useCallback for functions

②Use useMemo for objects/arrays

上面这个说法过时了,avoid inline functions and objects说的太绝对了。但我还是把它保留,因为这个说法很流行。

在现代 React 开发中,“绝对禁止内联函数”被认为是一种过度优化(Over-optimization)。面试时,如果你能辩证地看待这个问题,会显得你更有经验。

以下是针对这个问题的深度解析,以及如何在面试中“专业地反驳”或补充:

  1. 为什么会有“避免内联函数”的说法?

这个观点的核心担忧是 引用相等性(Reference Equality)

  1. 为什么这种说法“不准确”?
  1. 面试时的“标准标准回答” (The "Senior" Answer)

当面试官提到“避免内联函数”时,你可以这样回答:

中文逻辑:

“‘避免内联函数’这个原则在 React 中需要视情况而定

它的主要目的是为了保持引用稳定。如果一个内联函数被传递给了包裹了 React.memo 的子组件,或者作为 useEffect 的依赖项,那么内联函数确实会导致不必要的重绘或 Effect 的重复执行。

但是,对于原生 HTML 标签,或者没有性能瓶颈的普通组件,内联函数是完全可以接受的。过度使用 useCallback 反而会增加代码复杂度。

所以我的原则是:先编写简洁的内联代码,只有在 Profiler 检测到性能瓶颈,或者需要保持引用一致性时,才去使用 useCallback 优化。

  1. 英文面试版本 (Pro Interview Version)

"The advice to avoid inline functions is not an absolute rule; it's about managing reference stability.

The real issue isn't the creation of the function itself—React handles that very efficiently. The issue is that a new function reference can break memoization in child components (using React.memo) or trigger unnecessary useEffect calls.

If I'm passing a function to a native element like a <button>, an inline function is perfectly fine. However, if I'm passing it to a heavy, memoized component, I would wrap it in useCallback to ensure the child doesn't re-render unless its actual logic changes.

My philosophy is: Don't prematurely optimize. I prefer clean, readable code with inline functions first, and only optimize when the Profiler shows a real performance bottleneck."

 

上面的步骤要理解,然后简要的答案先说出来:

When optimizing React performance, I follow a systematic approach: Measure, Identify, and then Refine.

First, I use the React DevTools Profiler to identify 'hot' components—those that render too frequently or take too long.

A common issue I look for is unnecessary re-renders caused by broken memoization. I check if stable references are being lost because inline functions or objects are being passed as props to components wrapped in React.memo. In these specific cases, I use useCallback or useMemo to stabilize those references and ensure memoization actually works.

However, I don't just wrap everything in hooks. I also look for architectural smells, such as state being 'lifted' too high. I often optimize by pushing state down to leaf components or using component composition to isolate expensive branches from parent updates.

Finally, for UI-level bottlenecks, I implement Windowing for large lists or Code Splitting to reduce the main thread load. My goal is always to solve the root cause with the simplest effective solution.

面试加分点:

  1. 明确了“什么时候”优化内联函数:

    • 原话:“I check if I accidentally introduced inline functions...”(听起来像是在避错)
    • 优化:“...passed as props to components wrapped in React.memo.”(这表明你清楚:只有配合 memo 时,内联函数才是问题。这非常加分!)
  2. 引入了“状态下放” (Pushing State Down):

    • 这是 React 官方推荐的首选优化方案,比 useMemo 更优雅。提到它说明你理解“组合优于配置”。
  3. 使用了专业词汇:

    • Hot components (高频渲染组件)
    • Architectural smells (架构层面的不合理处)
    • Leaf components (叶子节点/底层组件)
  4. 闭环逻辑:

    • 结尾强调“用最简单的方案解决根本问题”,展现了工程师的务实态度。

2、how do you prevent a login page from being accessible after the user is logged in?

The general idea is:If the user is already authenticated, redirect them away from the login page.

  1. Using React Router (most common)

You check the auth state, and if the user is logged in, redirect them:

Explanation:

This ensures the login page is never visible to authenticated users.

  1. With a Protected Route Wrapper

Sometimes I create a wrapper:

Then wrap the route:

  1. Server-side check (if SSR or backend routing)

If the backend renders the page, the server can also redirect if the session exists.

理解上面的内容后,简要回答:

I prevent the login page from being accessible after login by checking whether the user is authenticated. If the user is already logged in, I immediately redirect them to a protected page like the dashboard. In React Router, this usually means returning a <Navigate> component when user exists. This ensures the login page is only visible to unauthenticated users.

3、how do you handle API errors gracefully in the UI?

  1. Show a clear, user-friendly message

Users should never see raw server errors like “500 Internal Server Error”.

Example:

This keeps the UI clean and understandable.

  1. Use try/catch around API calls

In React components or services:

Then the UI reacts to that error state.

  1. Display fallback UI

For example:

  1. Handle different error types

I often show different messages depending on the error:

This makes the UI feel professional and predictable.

  1. If using React Query

React Query makes this much easier:

React Query automatically gives:

So the UI can handle errors more gracefully.

理解上面之后,简要的回答:

I handle API errors by wrapping network calls in try/catch or using libraries like React Query / Axios, capturing both HTTP-error responses and network exceptions. I store the error state (e.g. using useState or React Query’s error / isError flags), and show a user-friendly fallback UI — such as an error message, a toast/notification, or a retry button wrapped in a conditional render. For critical component errors I can also use a global error boundary (via ErrorBoundary) to catch rendering or lifecycle exceptions so the whole UI doesn’t break. For HTTP status codes I differentiate behaviors — e.g. 401 leads to redirect to login, 403 shows “access denied”, 400 shows validation feedback. I may also implement retry logic or exponential-backoff on failures (especially for transient network errors) and log errors (to console or a logging service) for debugging.

4、a component is fetching the same data multiple times unneccessarily. How do you fix it?

  1. Fix the useEffect dependency array

One of the most common causes is a missing or incorrect dependency array:

❌ Bad (fetch runs every render)

✅ Good (runs only once on mount)

Or if dependencies are required, ensure they don’t change on every render.

  1. Memoize functions with useCallback

If the fetch function is declared inline and passed to children or used inside effects, it may be recreated every render, causing repeated calls.

❌ Bad

✅ Good

  1. Memoize computed values with useMemo

If parameters for your fetch are created inline (like an object), the reference changes every time:

✔️

  1. Lift state up (avoid fetching in many components)

Sometimes multiple sibling components fetch the same data.

Solution:

This way the data is fetched once and shared.

  1. Use a data-fetching library (React Query)

Tools like React Query automatically:

React Query example:

Duplicate calls are automatically prevented.

  1. Ensure no conditional renders cause re-mounting

Some developers accidentally remount a component repeatedly:

If isOpen toggles repeatedly, the component unmounts and remounts, triggering useEffect again.

Fix:

理解上面的内容后,简要的回答:

First, I check the useEffect dependency array — missing or unstable dependencies often cause repeated fetch calls. Then I make sure the fetch function is memoized with useCallback and any params with useMemo, so they don’t change every render. If several components need the same data, I move the fetching logic into a global store, such as zustand, so the data is fetched once and reused everywhere. For even more control, I use libraries like React Query, which provide request deduplication, caching, and stale-while-revalidate behavior out of the box.

 

In short: stabilize dependencies, avoid remounting, and centralize or cache the data so it only gets fetched once.

5、how do you optimize bundle size in a large react app?

可以这样想:think of this like you are travelling, you don't take your complete cupboard or wardrobe with you, you take neccessary some part of it in the travel.

Just like that, whenever you writing thousands of files in your app, you don't need to ship everything to the production.So you need to bundle it and organize it somehow so that it will take minimum size on the user's device and it will be efficient for the performance.

  1. Code splitting → use React.lazy or Suspense
  2. Tree Shaking → use vite or webpack to remove unused imports
  3. Dynamic imports → use dynamic imports, import() to avoid some code to be bundled in the main chunk
  4. Compress assets → images or fonts

理解了上面的内容之后,简要回答:

I usually optimize bundle size by focusing on code splitting, dependency management, and build-time optimizations. First, I implement route-level code splitting using React.lazy and Suspense, so the app only loads what’s needed for the current page. For heavier features, I use dynamic imports or component-level lazy loading to avoid shipping large chunks upfront. I also regularly analyze the bundle using tools like Webpack Bundle Analyzer or Vite’s analyze plugin to identify large or unused dependencies. If a library is too heavy, I try to replace it with a smaller alternative, remove unused code, or tree-shake it. On the build side, I make sure features like tree-shaking, minification, and dead-code elimination are enabled, and I avoid importing entire libraries when I only need specific modules. For assets, I optimize images, use *.svg components instead of PNGs, and rely on CDNs where possible.

 

Overall, the approach is: split the code, trim unnecessary dependencies, enable build optimizations, and continuously analyze the bundle to keep it lean.

6、how do you handle a form with 20+ fields efficiently?

当面试官问large forms,他们想要看到你是否能够优化form、维持状态的能力。

这是Shubham Kulkarni | Coding and Interviews这位老师的回答要点。

1、use form management library like react hook form,

2、structure the form to logical steps or sections.

3、use controlled components,

4、use zod library to validate.

 

下面是chatgpt的回答:

✅ 1. Group related fields into logical sections

Don’t treat 20 fields as 20 individual states. Instead, think of your form as sections:

This gives you:

✔ Better UI/UX ✔ Smaller components ✔ Cleaner validation

Example structure:

✅ 2. Use a form library — don’t manage 20 states manually

Best option: React Hook Form (RHF)

It handles:

For 20+ fields, RHF is definitely better than useState or even Formik.

Example:

✅ 3. Store all form values in one place (not 20 states)

For large forms, do NOT use:

Instead:

Or if using useState manually:

✅ 4. Extract repeating field logic into reusable components

If many fields share:

Create a component:

Now your form becomes:

✅ 5. Use zod to avoid manual checks

With 20+ fields, writing if (!name) error... everywhere becomes painful.

Use Zod:

Integrate with RHF:

Now all validation is centralized and reusable.

✅ 6. Use dynamic generation (optional but powerful)

If fields share patterns, define them as config:

Render automatically:

Great for 20–100 fields.

✅ 7. Split the form into tabs or steps if possible

For UX improvement:

Use a stepper or wizard.

Better:

✔ Less intimidating ✔ Faster rendering ✔ Validation per step

✅ 8. Memoize heavy components

For example, expensive dropdowns.

RHF already minimizes re-renders, but memoization helps further.

🧪 9. For huge forms → Use RHF + Suspense + lazy-loaded sections

If your sections are large:

Better performance for enterprise apps.

理解上面的内容之后,就可以背诵答案了:

When handling large forms with over 20 fields, my approach focuses on maintainability and performance.

First, I modularize the form by grouping related fields into logical sections or sub-components. This keeps the code clean and the UI user-friendly.

To manage state efficiently, I use React Hook Form instead of multiple useState hooks. This centralizes the form state and significantly reduces unnecessary re-renders, which is crucial for performance at this scale.

For validation, I integrate Zod for schema-based, type-safe validation. This keeps all the rules in one place and ensures consistency. I also extract common patterns into reusable input components—and if the form is highly repetitive, I’ll drive the fields from a config object to minimize boilerplate.

Finally, if the UX feels overwhelmed, I’ll break the form into multi-step wizards or tabs.

 

In short, my strategy is: centralized state, schema-driven validation, and a modular component structure.

7、your react app needs to support dark mode.How do you implement it?

面试管想听到的要点就是:the theme state should be global, so whenever you toggle the theme at the global state, it will be auto reflected in the children level.

1、I will check whether the dark mode is user preference based or system based.

2、if it's system based.I will use prefers-color-scheme media query to detect system preference on first load.then set the theme mode.

3、if it's user mode, I often rely on react context or redux to set global state, and rely on CSS variables or tailwindcss to set dark mode.

简要回答:

To implement dark mode in a React app, I usually manage a theme state at the top level, using React Context or a global store like Zustand. I store the user’s preference in localStorage so it persists across sessions, and I use a toggle button in the UI to switch between light and dark themes. For styling, I often rely on CSS variables or a utility framework like Tailwind CSS, which supports dark mode with the dark: variant. Components then automatically adapt by referencing the theme variables, and I can also add a class like dark on the root element to switch the entire app.

 

In short, the approach is: store theme in global state, persist the preference, and style components using CSS variables or a framework that supports dark mode

8、how do you prevent XSS(Cross-Site Scripting) in frontend apps?

关键词拆解:

  1. XSS (Cross-Site Scripting)

    • 一种常见的前端安全漏洞,攻击者可以注入恶意脚本到网页,执行在其他用户浏览器中。
    • 可能导致 cookie泄露、用户数据被篡改、劫持会话 等。
  2. Frontend apps

    • 前端应用(React / Vue / Angular 等),主要是 浏览器端防护

核心考点:

拆解小问题:

  1. 为什么会发生 XSS?

    • 用户输入未经处理直接插入到 DOM → 执行脚本
  2. 前端可以做什么?

    • 不要插入未处理的 HTML
    • 框架的自动转义机制
    • 对必须插入的 HTML 做 清理/过滤
  3. 可用工具 / 方法?

    • React 自动转义 {userInput}
    • dangerouslySetInnerHTML + DOMPurify
    • 禁用 eval()
    • 内容安全策略 (CSP)

To prevent XSS, I implement a defense-in-depth strategy, focusing on both safe coding patterns and environmental security.

First, I leverage React’s default escaping. Since React automatically escapes values in JSX, I treat it as the first line of defense. I strictly avoid dangerouslySetInnerHTML unless there’s a specific requirement. If it's unavoidable, I always pipe the content through DOMPurify to strip out malicious scripts.

Second, for URL-based attacks, I sanitize dynamic links to prevent javascript: protocol injection. I ensure any user-provided URLs are validated against a whitelist of safe protocols like http: or https:.

Third, I advocate for a strong Content Security Policy (CSP). By configuring CSP headers to disallow unsafe-inline scripts and restricting script sources to trusted domains, we can stop XSS even if a vulnerability exists in the code.

Finally, I ensure all third-party dependencies are regularly audited using tools like npm audit to avoid indirect vulnerabilities.

In summary, my approach is: Escape by default, Sanitize when necessary, and enforce CSP for environment-level security.

 

(为了防止 XSS,我采取了深度防御策略,重点关注安全编码模式和环境安全。)

(首先,我利用 React 的默认转义。JSX 会自动转义变量,这是第一道防线。我严格避免使用 dangerouslySetInnerHTML,除非有特殊需求;如果非用不可,我一定会用 DOMPurify 过滤掉恶意脚本。)

(第二,针对基于 URL 的攻击,我会对动态链接进行清理,防止 javascript: 伪协议注入。我会确保用户提供的 URL 符合 httphttps 的白名单。)

(第三,我主张使用强有力的 CSP(内容安全策略)。通过配置 CSP 响应头来禁用 unsafe-inline 脚本并限制信任域名,即使代码中存在漏洞,也能阻止 XSS 执行。)

(最后,我会定期使用 npm audit 等工具审计第三方依赖,以避免间接漏洞。)

(总而言之,我的方法是:默认转义、必要时清理、并强制执行 CSP 以实现环境级安全。)

 

9、how do you handle offline/online state gracefully in react with service workers?

1️⃣ 题目关键词

  1. Offline/Online state

    • 意思是用户的网络状态:在线(online)还是离线(offline)。就好像discord、reddit这些网站,用户登录之后,会显示鲜活的头像,如果用户网断了,那么头像就显示黑白色。
    • 你的应用需要知道用户是在线还是离线,并作出对应处理。
  2. Gracefully

    • 不只是知道状态,还要让用户体验顺畅。
    • 例如:显示提示、缓存数据、避免应用崩溃。
  3. React

    • 说明你需要在 React 组件里管理这个状态。
    • 可能涉及 stateContextRedux
  4. Service Workers

    • 浏览器的一种后台脚本,用来缓存资源和数据,实现 离线功能
    • 它允许你的应用在没有网络时仍然能运行一部分功能。

2️⃣ 拆解后的思路

你可以把题目拆解成三个小问题:

(A) 如何在 React 中检测在线/离线状态?

(B) 如何用 Service Worker 支持离线功能?

(C) 如何在重新上线时同步数据?

3️⃣ 组合成回答框架

  1. 检测状态navigator.onLine + online/offline 事件
  2. 更新 UI → 显示横幅、禁用某些功能、提示用户
  3. 离线功能 → Service Worker 缓存静态资源和 API 数据
  4. 重新上线同步 → background sync 或手动发送缓存的请求

老师的要点:

1、I will use navigator.onLine API provided by the browser, to detect network status. And listen to the online and offline events.

2、use service workers to cache critical assets and API responses.

 

To handle offline and online states in a React app, I usually combine browser APIs with Service Workers.

First, I detect network status using the navigator.onLine property and listen to the online and offline events, updating a global state or React Context so components can react accordingly. For example, I can show a banner or toast to inform users they are offline.

Second, I use a Service Worker—for example, via Workbox—to cache critical assets and API responses. This allows the app to function in offline mode and serve cached content.

For data syncing, when the user goes back online, I can implement background sync to send queued updates to the server.

 

In short, my approach is: listen to network events, update UI reactively, cache resources with a Service Worker, and optionally queue requests for later syncing to provide a seamless offline/online experience.

10、Production is not getting the latest deployed update unless in incognito.How do you solve this?

关键词拆解:

  1. Production is not getting the latest update

    • 用户在生产环境访问网站时,看到的仍是旧版本。
    • 说明前端部署了新版本,但浏览器加载的是缓存的旧文件。
  2. Unless in incognito

    • 这里的隐身模式,指的是浏览器的无痕模式窗口
    • 在隐身模式下正常显示最新版本
    • 隐身模式通常不会使用浏览器缓存或 Service Worker 缓存 → 问题在 缓存策略

核心考点:

拆解小问题:

  1. 为什么普通用户看到旧版本?

    • 浏览器缓存旧 JS/CSS 文件,比如说打包后的main.js,这个文件名没有变化的话,浏览器不会默认获取新的。
    • CDN 缓存旧文件
    • Service Worker 缓存旧资源
  2. 为什么隐身模式正常?

    • 隐身模式不会使用旧缓存 → 能直接获取最新资源
  3. 如何解决?

    • 强制浏览器/用户获取最新文件,Use content hashing for JS/CSS filenames in the build process
    • 设置正确的 HTTP 缓存策略
    • 或在 Service Worker 中处理缓存更新

简要回答:

This is a classic cache invalidation issue. When a site works in incognito but not in a normal tab, it means the browser is stale-loading resources from the local cache.

To resolve this permanently, I focus on three layers:

First, I ensure the build pipeline uses Content Hashing. By appending a unique hash to each JS and CSS filename, we force the browser to download the new version because the URL has changed.

Second, I'll audit the HTTP Cache-Control headers, specifically for the index.html. Since the HTML file is the entry point that references the hashed bundles, it must be set to no-cache or max-age=0. This ensures the browser re-validates with the server every time to see if there's a new index.html.

Third, if the app uses a Service Worker, I'll implement an update and skip-waiting logic. I'll make sure the Service Worker detects the new version and prompts the user to refresh, or automatically takes over the page to clear the old cache.

In summary, the key is to ensure immediate invalidation of the entry file (HTML) while leveraging long-term caching for hashed assets."

(这是一个经典的缓存失效问题。如果无痕模式正常而普通模式不正常,说明浏览器正在从本地缓存中加载旧资源。)

(为了彻底解决这个问题,我会从三个层面入手:)

(第一,我会确保构建流水线使用了内容哈希。通过给每个 JS 和 CSS 文件名添加唯一的哈希值,由于 URL 变了,浏览器会被强制下载新版本。)

(第二,我会审计 HTTP 缓存头,特别是 index.html 的配置。因为 HTML 是入口文件,它引用了带哈希的资源包,所以必须设置为 no-cachemax-age=0。这能确保浏览器每次都向服务器验证是否有新的入口文件。)

(第三,如果应用使用了 Service Worker,我会实现 update 和 skip-waiting 逻辑。确保 Service Worker 能检测到新版本并提示用户刷新,或者自动接管页面以清除旧缓存。)

(总而言之,核心在于确保入口文件(HTML)立即失效,同时利用哈希资源的长效缓存。)